﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows;
using GBL.Repository.CoatOfArms;
using GBL.Repository.Resources;
using GBlason.Common.Converter;
using GBlason.Culture;
using GBlason.Properties;
using GBlason.ViewModel;
using GBlason.ViewModel.CoatOfArm;
using GBlason.ViewModel.Contract;
using GBlasonLogic.Rules;
using GBlasonLogic.Tools;

namespace GBlason.Common.CustomCommand
{
    /// <summary>
    /// Commmand manager for the add of a new layer (or several new layer) divising a divisible area
    /// </summary>
    public class AddDivisionCommand : CommandGeneric
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="AddDivisionCommand"/> class.
        /// </summary>
        /// <param name="ownertype">The ownertype.</param>
        public AddDivisionCommand(Type ownertype)
            : base("Add Division", ownertype)
        {
            _addedDivision = new Collection<DivisionViewModel>();
        }

        private IDivisible _parentBefore;
        private CoatOfArmComponent _componentParent;

        private IEnumerable<DivisionViewModel> _addedDivision;

        /// <summary>
        /// Checks before continue the action.
        /// </summary>
        /// <returns></returns>
        private bool Check()
        {
            if (Parameter == null || Parameter.FileTargeted == null || Parameter.ObjectTargeted == null || Parameter.Parameter == null)
                return false;
            _parentBefore = Parameter.ObjectTargeted as IDivisible;
            if (_parentBefore == null)
                return false;
            _componentParent = _parentBefore as CoatOfArmComponent;
            return _componentParent != null;
        }

        public override void Do(CommandParameter parameter)
        {
            Parameter = parameter;
            if (!Check()) return;

            //appel de la zone logique seulement la premiere fois ! pour ajouter tous les elements nécessaires. pas facile parceqe les objects d'origines sont pas a jour ...
            var constraintParent = _parentBefore.GetDivisionsConstraints();
            var constraintCurrent = new ConstraintDivisionSet
            {
                TypeOfDivision = (DivisionType)Parameter.Parameter
            };

            var divisionToAdd = DivisionManager.CreateNewDivision(constraintParent, constraintCurrent).ToList();
            _addedDivision = divisionToAdd.Select(div => div.ConvertToViewModel()).ToList();

            Redo();

            //sauvegarde, c'est affreux, je peux pas le faire dans la classe abstraite parceque c'est cette instance que je dois cloner :(
            //copie de code pour tous les execute !!
            parameter.FileTargeted.CommandsApplied.AddCommandHistory((AddDivisionCommand)Clone());
        }

        /// <summary>
        /// Undoes this instance.
        /// The Done flag have to be set in the overrides. It ought to always the case (after a undo, the action is undone)
        /// </summary>
        public override void Undo()
        {
            //we add a layer for the command
            if (Parameter == null || Parameter.FileTargeted == null || Parameter.ObjectTargeted == null || Parameter.Parameter == null)
                return;
            _parentBefore = Parameter.ObjectTargeted as IDivisible;
            if (_parentBefore == null)
                return;
            var componentParent = _parentBefore as CoatOfArmComponent;
            if (componentParent == null)
                return;
            //appel de la zone logique pour supprimer tous les elements nécessaires

            foreach (var component in _addedDivision)
            {
                _parentBefore.RemoveDivision(component);
            }

            Done = false;
        }

        /// <summary>
        /// Redoes this instance.
        /// Use the saved parameters, with some changement if necessary
        /// </summary>
        public override void Redo()
        {
            //we add a layer for the command
            if (Parameter == null || Parameter.FileTargeted == null || Parameter.ObjectTargeted == null || Parameter.Parameter == null)
                return;
            _parentBefore = Parameter.ObjectTargeted as IDivisible;
            if (_parentBefore == null)
                return;
            var componentParent = _parentBefore as CoatOfArmComponent;
            if (componentParent == null)
                return;

            foreach (var divVm in _addedDivision)
            {
                divVm.Parent = _componentParent;
                _parentBefore.AddDivision(divVm);
                _addedDivision.Where(c => c != divVm).ToList().ForEach(c => c.Constraints.Add(divVm));
            }

            //auto selection of the first new div
            var firstOrDefault = _addedDivision.FirstOrDefault();
            if (firstOrDefault != null)
            {
                firstOrDefault.IsSelected = true;
            }

            var cultureRm = new System.Resources.ResourceManager(typeof(BlasonVocabulary));
            Description = String.Format(CultureInfo.CurrentCulture,
                                        Resources.CommandDescAddDivision,
                                        cultureRm.GetString(Parameter.Parameter.ToString()),
                                        componentParent.ComponentName);

            Done = true;
        }
    }
}
